#pragma once

#include<iostream>
#include<string>
#include<queue>
#include"Cond.hpp"
#include"Mutex.hpp"

const int defultcap = 10;

using namespace CondModule;
using namespace MutexModule;

template<typename T>
class BlockQueue
{
    private:
        bool IsFull()
        {
            return _q.size() >= _cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = defultcap)
            :_cap(cap), _csleep_num(0), _psleep_num(0)
        {
        }
        void Equeue(const T &in)
        {
            {
                LockGuard LockGuard(_mutex);
                //生产者调用
                while(IsFull())
                {
                    //满的时候生产者线程应该进行等待
                    //1.pthread_cond_wait调用成功，挂起当前线程之前，要先自动释放锁
                    //2.当线程被唤醒的时候，默认在临界区中被唤醒，
                    //要从pthread_cond_wait成功返回，需要让当前线程，重新申请锁_mutex
                    //3.如果我被唤醒，但是申请锁失败了，我就会在锁上阻塞等待
                    _psleep_num++;
                    std::cout << "生产者，进入休眠了: _psleep_num" << _psleep_num << std::endl;

                    _full_cond.Wait(_mutex);
                    _psleep_num--;
                }
                //队列有空间
                _q.push(in);

                if(_csleep_num > 0)
                {
                    _empty_cond.Signal();
                    std::cout<<"唤醒消费者"<<std::endl;
                }
            }
        }
        T Pop()
        {
            T Data;
            {
                //消费者调用
                LockGuard lockguard(_mutex);

                while (IsEmpty())
                {
                    _csleep_num++;
                    _empty_cond.Wait(_mutex);
                    _csleep_num--;
                }
                Data = _q.front();
                _q.pop();

                if(_psleep_num > 0)
                {
                    _full_cond.Signal();
                    std::cout<<"唤醒消费者"<<std::endl;
                } 
            }
            return Data;
        }
        ~BlockQueue()
        {}

    private:
        std::queue<T> _q;//临界资源
        int _cap;//容量大小

        Mutex _mutex;
        Cond _full_cond;
        Cond _empty_cond;

        int _csleep_num;//消费者休眠的个数
        int _psleep_num;//生产者休眠的个数

};
